package com.stock.demo.framework.fun;

import android.util.ArrayMap;

/**
 * Created by XuZhaoyu on 2017/7/9.
 */

public class Functions {

    private static final String errorMessage = "Function does not exist.Had you invoke addFunction(*) to add this function or add to a wrong type?";

    public abstract static class BaseFunction {
        public String mFunctionName;

        public BaseFunction(String functionName) {
            mFunctionName = functionName;
        }
    }

    /**
     * 无参无反的方法
     */
    public abstract static class Function extends BaseFunction {

        public Function(String functionName) {
            super(functionName);
        }

        public abstract void function();
    }

    /**
     * 有参无反的方法
     *
     * @param <Params> 方法参数
     */
    public abstract static class FunctionWithParams<Params> extends BaseFunction {
        public FunctionWithParams(String functionName) {
            super(functionName);
        }

        public abstract void function(Params params);
    }

    /**
     * 无参有反的方法
     *
     * @param <Results> 方法返回值
     */
    public abstract static class FunctionWithResults<Results> extends BaseFunction {
        public FunctionWithResults(String functionName) {
            super(functionName);
        }

        public abstract Results function();
    }

    /**
     * 有参有反的方法
     *
     * @param <Params>  方法参数
     * @param <Results> 方法返回值
     */
    public abstract static class FunctionWithParamsAndResults<Params, Results> extends BaseFunction {
        public FunctionWithParamsAndResults(String functionName) {
            super(functionName);
        }

        public abstract Results function(Params params);
    }

    /**
     * 存放四类方法的集合
     */
    private ArrayMap<String, Function> mFunctionMap = new ArrayMap<>();
    private ArrayMap<String, FunctionWithParams> mFunctionWithParamsMap = new ArrayMap<>();
    private ArrayMap<String, FunctionWithResults> mFunctionWithResultsMap = new ArrayMap<>();
    private ArrayMap<String, FunctionWithParamsAndResults> mFunctionWithParamsAndResultsMap = new ArrayMap<>();

    /**
     * 调用无参无反的方法
     *
     * @param functionName 被调用方法的名字
     */
    public void invokeFun(String functionName) {
        Function function = mFunctionMap.get(functionName);
        if (function != null) {
            function.function();
        }
    }

    /**
     * 调用有参无反的方法
     *
     * @param functionName 被调用方法的名字
     * @param params       被调用方法的参数
     * @param <Params>     被调用方法的参数泛型
     */
    public <Params> void invokeFunWithParams(String functionName, Params params) {
        FunctionWithParams functionWithParams = mFunctionWithParamsMap.get(functionName);
        if (functionWithParams != null) {
            functionWithParams.function(params);
        }
    }

    /**
     * 调用无参有反的方法
     *
     * @param functionName 被调用方法的名字
     * @param clazz        被调用方法返回值的类（.class）
     * @param <Results>    被调用方法的返回值泛型
     * @return 被调用方法的返回值
     */
    public <Results> Results invokeFunWithResult(String functionName, Class<Results> clazz) {
        FunctionWithResults functionWithResults = mFunctionWithResultsMap.get(functionName);
        if (functionWithResults != null) {
            return clazz.cast(functionWithResults.function());
        }
        return null;
    }

    /**
     * 调用有参有反的方法
     *
     * @param functionName 被调用方法的名字
     * @param params       被调用方法的参数
     * @param clazz        被调用方法返回值的类（.class）
     * @param <Params>     被调用方法的参数泛型
     * @param <Results>    被调用方法的返回值泛型
     * @return 被调用方法的返回值
     */
    public <Params, Results> Results invokeFunWithParamsAndResults(String functionName, Params params, Class<Results> clazz) {
        FunctionWithParamsAndResults functionWithParamsAndResults = mFunctionWithParamsAndResultsMap.get(functionName);
        if (functionWithParamsAndResults != null) {
            return clazz.cast(functionWithParamsAndResults.function(params));
        }
        return null;
    }

    /**
     * 添加无参无反方法
     *
     * @param function 被添加的方法
     */
    public Functions addFunction(Function function) {
        if (function != null) {
            mFunctionMap.put(function.mFunctionName, function);
        }
        return this;
    }

    /**
     * 添加有参无反的方法
     *
     * @param function 被添加的方法
     */
    public Functions addFunction(FunctionWithParams function) {
        if (function != null) {
            mFunctionWithParamsMap.put(function.mFunctionName, function);
        }
        return this;
    }

    /**
     * 添加无参有反的方法
     *
     * @param function 被添加的方法
     */
    public Functions addFunction(FunctionWithResults function) {
        if (function != null) {
            mFunctionWithResultsMap.put(function.mFunctionName, function);
        }
        return this;
    }

    /**
     * 添加有参有反的方法
     *
     * @param function 被添加的方法
     */
    public Functions addFunction(FunctionWithParamsAndResults function) {
        if (function != null) {
            mFunctionWithParamsAndResultsMap.put(function.mFunctionName, function);
        }
        return this;
    }

}
